use std::{rc::Rc, cell::RefCell};

use crate::{instructions::base::{self, Instruction, BytecodeReader}, rtda::Frame};

// 把栈顶的两个int变量弹出，然后进行比较，满足条件则跳转。

// Branch if int comparison succeeds
#[derive(Debug, Default)]
pub struct IF_ICMPEQ {
    offset: i32
}

impl Instruction for IF_ICMPEQ {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 == v2 {
            base::branch(frame, self.offset)
        }
    }
}

#[derive(Debug, Default)]
pub struct IF_ICMPNE {
    offset: i32
}

impl Instruction for IF_ICMPNE {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 != v2 {
            base::branch(frame, self.offset)
        }
    }
}

#[derive(Debug, Default)]
pub struct IF_ICMPLT {
    offset: i32
}

impl Instruction for IF_ICMPLT {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 < v2 {
            base::branch(frame, self.offset)
        }
    }
}

#[derive(Debug, Default)]
pub struct IF_ICMPLE {
    offset: i32
}

impl Instruction for IF_ICMPLE {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 <= v2 {
            base::branch(frame, self.offset)
        }
    }
}

#[derive(Debug, Default)]
pub struct IF_ICMPGT {
    offset: i32
}

impl Instruction for IF_ICMPGT {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 > v2 {
            base::branch(frame, self.offset)
        }
    }
}

#[derive(Debug, Default)]
pub struct IF_ICMPGE {
    offset: i32
}

impl Instruction for IF_ICMPGE {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.offset = reader.read_i16() as i32;
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let (v1, v2) = _icmp_pop(frame.clone());
        if v1 >= v2 {
            base::branch(frame, self.offset)
        }
    }
}

fn _icmp_pop(frame: Rc<RefCell<Frame>>) -> (i32, i32) {
    let stack = frame.borrow().get_operand_stack();
    let v2 = stack.borrow_mut().pop_int();
    let v1 = stack.borrow_mut().pop_int();
    (v1, v2)
}